package com.david.http.http.util

import android.util.Log
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.lastOrNull
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.zip
import kotlinx.coroutines.launch


fun <T> Flow<T>.request(
    lifecycleOwner: LifecycleOwner,
    isOnlyResume: Boolean = true,
    block: (T) -> Unit
) {
    lifecycleOwner.lifecycleScope.apply {
        if (isOnlyResume) {
            launch {
                lifecycleOwner.repeatOnLifecycle(Lifecycle.State.RESUMED) {
                    this@request.onStart {
                        Log.e("error", "request onStart")
                    }.catch {
                        Log.e("error", "request error: ${it.message}")
                    }.onCompletion {
                        Log.e("error", "request onCompletion error: ${it?.message}")
                    }.collectLatest {
                        block(it)
                    }
                }
            }
        } else {
            launch {
                this@request.onStart {
                    Log.e("error", "request onStart")
                }.catch {
                    Log.e("error", "request error: ${it.message}")
                }.onCompletion {
                    Log.e("error", "request onCompletion error: ${it?.message}")
                }.collectLatest {
                    block(it)
                }
            }
        }
    }
}

/**
 * 直接返回Pair结果的zip，对于简单的结果接收可用（不用对数据混合处理时）
 */
fun <T1, T2> Flow<T1>.zip2(flow2: Flow<T2>): Flow<Pair<T1, T2>> {
    return this.zip(flow2) { one, two ->
        Pair(one, two)
    }
}

fun <T1, T2, T3> Flow<T1>.zip3(
    flow2: Flow<T2>?,
    flow3: Flow<T3>?
): Flow<Triple<T1?, T2?, T3?>> {
    return flow {
        coroutineScope {
            val f1Value = async { lastOrNull() }
            val f2Value = async { flow2?.lastOrNull() }
            val f3Value = async { flow3?.lastOrNull() }

            emit(Triple(f1Value.await(), f2Value.await(), f3Value.await()))
        }
    }.flowOn(Dispatchers.IO)
}